﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Xml.Linq;
using Microsoft.Practices.ServiceLocation;
using System.Windows;
using System.IO;
using System.Windows.Input;

namespace DynamicUIFramework
{
    public class DesignerStackPanel: StackPanel, IPanel
    {
        public DesignerStackPanel()
        {
            //Background = Brushes.White;
            if (DesignerContext.IsInDesignMode)
            {
                this.ContextMenu = new ContextMenu();
                MenuItem mi = new MenuItem { Header = "Elements" };
                foreach (var pt in (ServiceLocator.Current as MefServiceLocator).CompositionContainer.Catalog.Parts)
                {
                    foreach (var ed in pt.ExportDefinitions)
                    {
                        object type = ed.Metadata["ExportTypeIdentity"];
                        if (type.ToString().Equals(typeof(IElement).FullName))
                        {
                            MenuItem item = new MenuItem { Header = ed.ContractName, Tag = ed.ContractName };
                            item.Click += (s, e) =>
                            {
                                IElement element = ServiceLocator.Current.GetInstance<IElement>((s as MenuItem).Tag.ToString());
                                DesignerItem di = new DesignerItem();
                                di.Content = element;
                                this.Children.Add(di);
                            };
                            mi.Items.Add(item);
                        }
                    }
                }

                this.ContextMenu.Items.Add(mi);


                MenuItem part = new MenuItem { Header = "Parts" };
                PartController pc = ServiceLocator.Current.GetInstance<PartController>();
                if (pc != null)
                {
                    foreach (var p in pc.GetParts())
                    {
                        MenuItem item = new MenuItem { Header = p, Tag = p };
                        item.Click += (s, e) =>
                        {
                            FrameworkElement fe = pc.GetPartInstance((s as MenuItem).Tag.ToString());
                            DesignerItem di = new DesignerItem();
                            di.Content = fe;
                            this.Children.Add(di);
                        };
                        part.Items.Add(item);
                    }
                }
                this.ContextMenu.Items.Add(part);

                MenuItem mode = new MenuItem { Header = "Orientation" };
                MenuItem v = new MenuItem { Header = "Vertical" };
                MenuItem h = new MenuItem { Header = "Horizontal" };
                v.Click += (s, e) => { this.Orientation = System.Windows.Controls.Orientation.Vertical; };
                h.Click += (s, e) => { this.Orientation = System.Windows.Controls.Orientation.Horizontal; };
                mode.Items.Add(v);
                mode.Items.Add(h);
                this.ContextMenu.Items.Add(mode);
            }
        }

        public XElement Save()
        {
            XElement ele = new XElement("StackPanel");
            ele.SetAttributeValue("target", this.GetType().FullName);
            ele.SetAttributeValue("orientation", this.Orientation.ToString());
            foreach (var item in this.Children)
            {
                DesignerItem di = item as DesignerItem;
                if (di.Content is IElement)
                {
                    IElement target = di.Content as IElement;
                    XElement child = new XElement("Element");
                    child.SetAttributeValue("contractName", target.GetType().Name);
                    FrameworkElement fe = target as FrameworkElement;
                    child.SetAttributeValue("referenceResourceKey", string.IsNullOrEmpty(target.ReferenceResourceKey) ? string.Empty : target.ReferenceResourceKey);

                    ICommandSource cs = target as ICommandSource;
                    if (cs != null)
                    {
                        if (cs.Command != null)
                        {
                            CommandController cc = ServiceLocator.Current.GetInstance<CommandController>();
                            child.SetAttributeValue("command", cc.GetCommandName(cs.Command));
                        }
                        if (cs.CommandParameter != null)
                        {
                            child.SetAttributeValue("commandParameter", cs.CommandParameter);
                        }
                    }

                    ContentControl con = target as ContentControl;
                    if (con != null)
                    {
                        if (con.Content != null && con.Content.GetType().Equals(typeof(string)))
                        {
                            child.SetAttributeValue("content", con.Content.ToString());
                        }
                    }


                    ele.Add(child);
                }
                else
                {
                    UserControl target = di.Content as UserControl;
                    XElement child = new XElement("Part");
                    child.SetAttributeValue("path", target.Tag.ToString());
                    ele.Add(child);
                }
            }

            return ele;
        }

        public void Load(XElement ele)
        {
            XAttribute orientation = ele.Attribute("orientation");
            if (orientation != null)
                this.Orientation = (System.Windows.Controls.Orientation)Enum.Parse(typeof(System.Windows.Controls.Orientation), orientation.Value);
            this.Children.Clear();
            foreach (var item in ele.Elements())
            {
                if (item.Name.LocalName.Equals("Element"))
                {
                    string contractName = item.Attribute("contractName").Value;
                    IElement element = ServiceLocator.Current.GetInstance<IElement>(contractName);
                    DesignerItem di = new DesignerItem();
                    di.Content = element;

                    string referenceResourceKey = item.Attribute("referenceResourceKey") == null ? string.Empty : item.Attribute("referenceResourceKey").Value;
                    element.ReferenceResourceKey = referenceResourceKey;
                    FrameworkElement fe = element as FrameworkElement;
                    if (string.IsNullOrEmpty(referenceResourceKey))
                        fe.SetResourceReference(FrameworkElement.StyleProperty, element.GetType());
                    else
                    {
                        try
                        {
                            fe.SetResourceReference(FrameworkElement.StyleProperty, referenceResourceKey);
                        }
                        catch
                        {
                            fe.SetResourceReference(FrameworkElement.StyleProperty, element.GetType());
                        }
                    }

                    ICommandSource cs = element as ICommandSource;
                    if (cs != null)
                    {
                        XAttribute xcomm = item.Attribute("command");
                        XAttribute xcommPara = item.Attribute("commandParameter");
                        if (xcomm != null && string.IsNullOrEmpty(xcomm.Value) == false)
                        {
                            CommandController cc = ServiceLocator.Current.GetInstance<CommandController>();
                            cs.GetType().GetProperty("Command").SetValue(cs, cc.GetCommand(xcomm.Value), null);
                        }
                        if (xcommPara != null && string.IsNullOrEmpty(xcommPara.Value) == false)
                        {
                            cs.GetType().GetProperty("CommandParameter").SetValue(cs, xcommPara.Value, null);
                        }
                    }

                    ContentControl con = element as ContentControl;
                    if (con != null)
                    {
                        XAttribute content = item.Attribute("content");
                        if (content != null)
                        {
                            if (con.Content == null || con.Content.GetType().Equals(typeof(string)))
                            {
                                con.Content = content.Value;
                            }
                        }
                    }


                    this.Children.Add(di);
                }
                else if (item.Name.LocalName.Equals("Part"))
                {
                    string path = item.Attribute("path").Value;
                    UserControl uc = XamlHelper.LoadXaml(path);
                    DesignerItem di = new DesignerItem();
                    di.Content = uc;
                    this.Children.Add(di);
                }
            }
        }
    }
}
